import socket
import threading
import time
import logging
from utils import SIPUtils
from xml_builder import XMLBuilder

logger = logging.getLogger('SIPClient')

class SIPClient:
    _instance = None
    
    def __new__(cls, config):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._init_client(config)
        return cls._instance
    
    def _init_client(self, config):
        self.config = config
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind((config.local_ip, config.local_port))
        
        self.ack_event = threading.Event()
        self.current_invite_call_id = None
        self.listener_thread = None
        self.keepalive_thread = None
        self.running = False
        self.message_handler = None
        self.registered = False
    
    def set_message_handler(self, handler):
        """设置消息处理回调函数"""
        self.message_handler = handler
    
    def register(self, max_retries=3):
        """注册到SIP服务器，带有重试机制"""
        for attempt in range(max_retries):
            logger.info(f"注册尝试 {attempt+1}/{max_retries}")
            
            # 首次注册（预期收到401）
            initial_request = self._create_register_request()
            response = self._send_register_request(initial_request)
            
            if not response:
                logger.warning("初次注册未收到响应")
                time.sleep(2)
                continue
                
            if "401 Unauthorized" not in response:
                logger.error(f"初次注册收到意外响应: {response[:200]}...")
                time.sleep(2)
                continue
                
            # 解析认证参数
            auth_params = SIPUtils.parse_www_authenticate(response)
            if not auth_params or 'nonce' not in auth_params or 'realm' not in auth_params:
                logger.error("无效的401认证响应")
                time.sleep(2)
                continue
                
            logger.info(f"获得认证参数: {auth_params}")
            
            # 发送认证注册请求
            auth_request = self._create_register_request(
                nonce=auth_params['nonce'],
                realm=auth_params['realm']
            )
            auth_response = self._send_register_request(auth_request)
            
            if not auth_response:
                logger.warning("认证注册未收到响应")
                time.sleep(2)
                continue
                
            if "200 OK" in auth_response:
                logger.info("注册成功！")
                self.registered = True
                return True
            else:
                logger.error(f"注册失败: {auth_response[:200]}...")
                time.sleep(2)
        
        logger.error("达到最大注册重试次数")
        return False
    
    def start(self):
        """启动SIP客户端"""
        if not self.registered:
            return False
            
        self.running = True
        self.listener_thread = threading.Thread(target=self._listen, daemon=True)
        self.listener_thread.start()
        
        # 启动保活线程
        self.keepalive_thread = threading.Thread(target=self._send_keepalives, daemon=True)
        self.keepalive_thread.start()
        
        return True
    
    def stop(self):
        """停止SIP客户端"""
        self.running = False
    
    def wait_for_ack(self, timeout=10):
        """等待ACK确认"""
        return self.ack_event.wait(timeout)
    
    def ack_received(self):
        """通知收到ACK"""
        self.ack_event.set()
    
    def send_message(self, content, content_type="Application/MANSCDP+xml"):
        """发送SIP MESSAGE"""
        call_id = f"{int(time.time() * 1000)}@{self.config.local_ip}"
        self.current_invite_call_id = call_id
        
        cseq = int(time.time() * 1000) % 999999
        
        message = (
            f"MESSAGE sip:{self.config.sip_server_id}@{self.config.domain} SIP/2.0\r\n"
            f"Via: SIP/2.0/UDP {self.config.local_ip}:{self.config.local_port};branch=z9hG4bK{int(time.time()*1000)}\r\n"
            f"Max-Forwards: 70\r\n"
            f"To: <sip:{self.config.sip_server_id}@{self.config.domain}>\r\n"
            f"From: <sip:{self.config.device_id}@{self.config.domain}>;tag={int(time.time()*1000)}\r\n"
            f"Call-ID: {call_id}\r\n"
            f"CSeq: {cseq} MESSAGE\r\n"
            f"Content-Type: {content_type}\r\n"
            f"Content-Length: {len(content.encode('utf-8'))}\r\n"
            f"\r\n"
            f"{content}"
        )
        
        self._send_to_server(message)
    
    def send_response(self, addr, status, request_headers, body="", content_type=""):
        """发送SIP响应"""
        # 构建响应
        response = f"SIP/2.0 {status}\r\n"
        
        # 添加必要的头
        if "Via" in request_headers:
            response += f"Via: {request_headers['Via']}\r\n"
        if "From" in request_headers:
            response += f"From: {request_headers['From']}\r\n"
        if "To" in request_headers:
            to_value = request_headers['To']
            if ";tag=" not in to_value:
                to_value += f";tag={int(time.time()*1000)}"
            response += f"To: {to_value}\r\n"
        if "Call-ID" in request_headers:
            response += f"Call-ID: {request_headers['Call-ID']}\r\n"
        if "CSeq" in request_headers:
            response += f"CSeq: {request_headers['CSeq']}\r\n"
        
        if content_type:
            response += f"Content-Type: {content_type}\r\n"
        
        response += f"Content-Length: {len(body.encode('utf-8'))}\r\n"
        response += "\r\n"
        
        if body:
            response += body
        
        self.sock.sendto(response.encode(), addr)
    
    def _create_register_request(self, nonce="", realm=""):
        """创建注册请求"""
        uri = f"sip:{self.config.sip_server_id}@{self.config.domain}"
        
        # 使用SIPUtils生成标准的SIP标识符
        branch = SIPUtils.generate_branch()
        tag = SIPUtils.generate_tag()
        call_id = SIPUtils.generate_call_id(self.config.local_ip)
        cseq = SIPUtils.generate_cseq()
        
        headers = [
            f"Via: SIP/2.0/UDP {self.config.local_ip}:{self.config.local_port};branch={branch};rport",
            f"From: <sip:{self.config.device_id}@{self.config.domain}>;tag={tag}",
            f"To: <sip:{self.config.sip_server_id}@{self.config.domain}>",
            f"Call-ID: {call_id}",
            f"CSeq: {cseq} REGISTER",
            f"Contact: <sip:{self.config.device_id}@{self.config.local_ip}:{self.config.local_port}>",
            f"Expires: {self.config.register_expires}",
            "Max-Forwards: 70",
            "User-Agent: GB28181 Device"
        ]
        
        if nonce and realm:
            response = SIPUtils.generate_digest(
                self.config.username,
                realm,
                self.config.password,
                "REGISTER",
                uri,
                nonce
            )
            auth_header = (
                f'Authorization: Digest username="{self.config.username}", '
                f'realm="{realm}", nonce="{nonce}", uri="{uri}", '
                f'response="{response}", algorithm=MD5'
            )
            headers.append(auth_header)
        
        headers.append("Content-Length: 0")
        return f"REGISTER {uri} SIP/2.0\r\n" + "\r\n".join(headers) + "\r\n\r\n"
    
    def _send_register_request(self, request, timeout=5):
        """发送注册请求并等待响应"""
        server = (self.config.sip_server_ip, self.config.sip_server_port)
        logger.debug(f"发送注册请求：{server}")
        
        try:
            self.sock.sendto(request.encode(), server)
            self.sock.settimeout(timeout)
            data, addr = self.sock.recvfrom(65535)
            response = data.decode()
            logger.debug(f"收到响应 {addr}: {response[:200]}...")
            return response
        except socket.timeout:
            logger.warning(f"等待响应超时 {timeout} 秒")
            return None
        except Exception as e:
            logger.error(f"发送注册请求错误: {str(e)}")
            return None
    
    def _wait_for_response(self, timeout=10):
        """等待响应"""
        try:
            self.sock.settimeout(timeout)
            data, addr = self.sock.recvfrom(4096)
            response = data.decode()
            logger.debug(f"收到响应 {addr}: {response[:200]}...")
            return response
        except socket.timeout:
            logger.warning(f"等待响应超时 {timeout} 秒")
            return None
        except Exception as e:
            logger.error(f"等待响应错误: {str(e)}")
            return None
    
    def _send_to_server(self, message):
        """发送消息到服务器"""
        server = (self.config.sip_server_ip, self.config.sip_server_port)
        self.sock.sendto(message.encode(), server)
    
    def _listen(self):
        """监听SIP消息"""
        self.sock.settimeout(1)
        logger.info(f"SIP监听器启动 {self.config.local_ip}:{self.config.local_port}")
        
        while self.running:
            try:
                # 增大接收缓冲区以支持大的INVITE消息（包含SDP）
                data, addr = self.sock.recvfrom(8192)
                
                # 添加调试日志，记录收到的消息类型和大小
                message = data.decode('utf-8', errors='ignore')
                first_line = message.split('\r\n')[0] if '\r\n' in message else message[:50]
                logger.info(f"[SIP监听器] 收到消息来自{addr}, 大小:{len(data)}字节, 类型:{first_line}")
                
                # 记录更多调试信息
                if "INVITE" in message:
                    logger.info(f"[SIP监听器] 发现INVITE消息!")
                if "MESSAGE" in message:
                    logger.info(f"[SIP监听器] 发现MESSAGE消息!")
                
                if self.message_handler:
                    # 在单独线程中处理消息
                    handler_thread = threading.Thread(
                        target=self.message_handler,
                        args=(data, addr),
                        daemon=True
                    )
                    handler_thread.start()
                else:
                    logger.warning(f"[SIP监听器] 收到消息但没有处理器: {first_line}")
                    logger.warning(f"[SIP监听器] 完整消息:\n{message}")
                    
            except socket.timeout:
                continue
            except UnicodeDecodeError as e:
                logger.error(f"[SIP监听器] 消息解码错误: {e}")
                logger.error(f"[SIP监听器] 原始数据: {data[:200]}")
                continue
            except Exception as e:
                logger.error(f"[SIP监听器] 监听器错误: {str(e)}")
                break
    
    def _send_keepalives(self):
        """发送心跳保活"""
        while self.running:
            time.sleep(30)  # 每30秒发送一次心跳
            if self.running:
                keepalive_xml = XMLBuilder.keepalive(self.config.device_id)
                self.send_message(keepalive_xml)
    
    def send_catalog_notify(self):
        """主动发送目录通知"""
        logger.info("正在发送目录通知...")
        
        # 生成新的SN
        import time
        sn = str(int(time.time()))
        
        catalog_xml = XMLBuilder.catalog_response(
            self.config.device_id,
            self.config.channel_id,
            self.config.local_ip,
            sn
        )
        logger.info(f"目录XML: {catalog_xml}")
        self.send_message(catalog_xml, content_type="Application/MANSCDP+xml")
        logger.info("目录通知已发送")